package com.peng.community.service.impl;

import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.peng.community.constant.CommunityConstant;
import com.peng.community.entity.DiscussPost;
import com.peng.community.event.EventProducer;
import com.peng.community.mapper.DiscussPostMapper;
import com.peng.community.service.DiscussPostService;
import com.peng.community.util.SensitiveFilter;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.HtmlUtils;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class DiscussPostServiceImpl implements DiscussPostService, CommunityConstant {

    @Autowired
    DiscussPostMapper discussPostMapper;


    @Value("${caffeine.posts.max-size}")
    private int maxSize;

    @Value("${caffeine.post.expire-time}")
    private int expireTime;


    //CAFFEINE核心组件：Cache, 代表一个缓存
    //子接口

    //存储帖子列表的缓存
    private LoadingCache<String, List<DiscussPost>> discussPostCache;

    //存储帖子数量的cache
    private LoadingCache<Integer, Integer> discussPostRowCache;

    @PostConstruct //初始化缓存
    public void init() {
        discussPostCache = Caffeine.newBuilder()
                .maximumSize(maxSize)
                .expireAfterWrite(expireTime, TimeUnit.SECONDS)
                .build(new CacheLoader<String, List<DiscussPost>>() {
                    @Nullable
                    @Override
                    //这是一个帮助缓存从数据库插叙数据的方法
                    public List<DiscussPost> load(@NonNull String s) throws Exception {
                        if (s.length() == 0) {
                            throw new IllegalArgumentException("参数不合法");
                        }
                        String[] ss = s.split(":");
                        if (ss.length != 2) {
                            throw new IllegalArgumentException("参数不合法");
                        }
                        int offset = Integer.parseInt(ss[0]), limit = Integer.parseInt(ss[1]);
                        log.info("从数据库查询数据");
                        return discussPostMapper.selectDiscussPosts(0,offset,limit,1);
                    }
                });
            discussPostRowCache = Caffeine.newBuilder()
                    .maximumSize(maxSize)
                    .expireAfterWrite(expireTime,TimeUnit.SECONDS)
                    .build(new CacheLoader<Integer, Integer>() {
                        @Nullable
                        @Override
                        public Integer load(@NonNull Integer integer) throws Exception {
                            log.info("从数据库查询数据");
                            return discussPostMapper.selectDiscussPostRows(integer);
                        }
                    });
    }

    @Override
    public List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int sortMode) {

        if (userId == 0 && sortMode == 1) {
            //只有当没有用户条件（查询所有）且按照热度排行时，才使用缓存
            String key = offset + ":" + limit;
            return discussPostCache.get(key);
        }

        log.info("从数据库查询数据");

        return discussPostMapper.selectDiscussPosts(userId, offset, limit, sortMode);
    }

    @Override
    public int selectDiscussPostRows(int userId) {
        if (userId == 0) {
            //只有查询所有的数量时才查询缓存
            discussPostRowCache.get(userId);
        }
        return discussPostMapper.selectDiscussPostRows(userId);
    }

    @Autowired
    SensitiveFilter sensitiveFilter;

    @Autowired
    EventProducer eventProducer;


    @Override
    public int insertDiscussPost(DiscussPost discussPost) {
        if (discussPost == null) {
            throw new IllegalArgumentException("参数不能为空");
        }
        //对标签进行转义并对敏感词进行过滤
        discussPost.setTitle(sensitiveFilter.filter(HtmlUtils.htmlEscape(discussPost.getTitle())));
        discussPost.setContent(sensitiveFilter.filter(HtmlUtils.htmlEscape(discussPost.getContent())));


        return discussPostMapper.insertDiscussPost(discussPost);
    }

    @Override
    public DiscussPost findDiscussPostById(int id) {
        return discussPostMapper.findDiscussPostById(id);
    }

    @Override
    public int updateConmentCount(int id, int commentCount) {
        return discussPostMapper.updateCommentCount(id, commentCount);
    }

    @Override
    public int updateScore(int id, long score) {
        return discussPostMapper.updateScore(id, score);
    }

    @Override
    public int updateStatus(int id, int status) {
        return discussPostMapper.updateStatus(id,status);
    }

    @Override
    public int updateType(int id, int type) {
        return discussPostMapper.updateType(id,type);
    }
}
